/*
   程序名称：bkbase.c
   程序内容：一些基本的函数
   程序作者：姚杰
   完成日期：2012 年 07 月 01 日
*/

#include "bkbase.h"

#include <sys/wait.h>
#include <stdarg.h>
#include <sys/statfs.h>

#if defined(BK_SCO)
   #include <sys/stropts.h>
#endif

#include <sys/timeb.h>

#ifdef __cplusplus
extern "C" {
#endif

#define MallocGarbage 0xa3
#define FreeGarbage   0xa5
#define TailChar      0xe1

typedef struct block_info {
   void *p;
   size_t size;
   struct block_info *next;
} BLOCK_INFO;

char BkTmpDir[500 + 1] = "";

static char ErrorLogFileName[500 + 1] = "";

#ifdef BK_DEBUG

static BLOCK_INFO *head = NULL;

static BLOCK_INFO *GetBlockInfo(void *PointerToGet);
static size_t SizeOfBlock(void *p);
static int CreateBlockInfo(void *NewPointer, size_t size);
static void FreeBlockInfo(void *PointerToFree);
static void UpdateBlockInfo(void *OldP, void *NewP, size_t NewSize);

static BLOCK_INFO *GetBlockInfo(void *PointerToGet)
{
   BLOCK_INFO *p;

   for ( p = head; p != NULL; p = p->next)
      if ( p->p == PointerToGet )
         break;

   BK_ASSERT(p != NULL);

   return p;
}

static size_t SizeOfBlock(void *p)
{
   return GetBlockInfo(p)->size;
}

static int CreateBlockInfo(void *NewPointer, size_t NewSize)
{
   BLOCK_INFO *p;
   void *TmpP;

   BK_ASSERT( NewPointer != NULL && NewSize != 0 );

   TmpP = malloc(sizeof(BLOCK_INFO));
   memcpy(&p, &TmpP, sizeof(void*));

   if ( p != NULL ){
      p->p = NewPointer;
      p->size = NewSize;
      p->next = head;
      head = p;
   }

   return p != NULL;
}

static void FreeBlockInfo(void *PointerToFree)
{
   BLOCK_INFO *p, *q;

   for ( q = NULL, p = head; p != NULL; p = p->next){
      if ( p->p == PointerToFree ){
         if ( q == NULL )
            head = p->next;
         else
            q->next = p->next;
         break;
      }
      q = p;
   }

   BK_ASSERT( p != NULL );

   memset(p, FreeGarbage, sizeof(BLOCK_INFO));
   free(p);
}

static void UpdateBlockInfo(void *OldPointer, void *NewPointer, size_t NewSize)
{
   BLOCK_INFO *p;

   BK_ASSERT( OldPointer != NULL && NewPointer != NULL && NewSize != 0 );

   p = GetBlockInfo(OldPointer);
   p->p = NewPointer;
   p->size = NewSize;
}

#endif

void BkDoNothing(void)
{
}

void BkAssert(char *FileName, int LineNo)
{
   fflush(stdout);
   fprintf(stderr, "\nAssertion failed: %s, line %d\n", FileName, LineNo);
   fflush(stderr);
   abort();
}

BK_UINT16 BkSwapShort(BK_UINT16 n)
{
   BK_UINT16 r;
   char *s1, *s2;

   s1 = (char*)&n + 1;
   s2 = (char*)&r;
   *s2++ = *s1--;
   *s2++ = *s1--;
   return r;
}

BK_UINT32 BkSwapLong(BK_UINT32 n)
{
   BK_UINT32 r;
   char *s1, *s2;

   s1 = (char*)&n + 3;
   s2 = (char*)&r;
   *s2++ = *s1--;
   *s2++ = *s1--;
   *s2++ = *s1--;
   *s2++ = *s1--;
   return r;
}

void BkRightTrim(char *s)
{
   long i;

   BK_ASSERT( s != NULL );

   for ( i = strlen(s) - 1; i >= 0 && s[i] == ' '; i--)
      s[i] = BK_EOS;
}

void BkFillChar(char *s, char c, size_t len)
{
   size_t i;

   BK_ASSERT( s != NULL );

   for ( i = 0; *s != BK_EOS && i < len; s++, i++)
      ;

   for ( ; i < len; i++)
      *s++ = c;

   *s = BK_EOS;
}

void BkFillLeft(char *s, char c, size_t len)
{
   int i;

   BK_ASSERT( s != NULL );

   i = strlen(s);

   if ( i >= len ){
      s[len] = BK_EOS;
      return;
   }

   memmove(s + len - i, s, i + 1);
   memset(s, c, len - i);
}

void BkToLower(char *s)
{
   BK_ASSERT( s != NULL );

   for ( ; *s != BK_EOS; s++)
      if ( *s >= 'A' && *s <= 'Z' )
         *s += 'a' - 'A';
}

void BkToUpper(char *s)
{
   BK_ASSERT( s != NULL );

   for ( ; *s != BK_EOS; s++)
      if ( *s >= 'a' && *s <= 'z' )
         *s -= 'a' - 'A';
}

int BkIsEmptyString(const char *s)
{
   return s == NULL || s[0] == BK_EOS;
}

void BkHexToAsc(const void *HexBuf, char *AscBuf, size_t HexLen)
{
   int c;
   size_t i;
   const unsigned char *p;

   BK_ASSERT( HexBuf != NULL && AscBuf != NULL );

   for ( p = (const unsigned char*)HexBuf, i = 0; i < HexLen; i++, p++){
      c = *p / 16;
      if ( c >= 0 && c <= 9 )
         *AscBuf++ = c + '0';
      else
         *AscBuf++ = c - 10 + 'A';
      c = *p % 16;
      if ( c >= 0 && c <= 9 )
         *AscBuf++ = c + '0';
      else
         *AscBuf++ = c - 10 + 'A';
   }
}

void BkAscToHex(void *HexBuf, const char *AscBuf, size_t HexLen)
{
   int c;
   size_t i;
   unsigned char *p;

   BK_ASSERT( HexBuf != NULL && AscBuf != NULL );

   for ( p = (unsigned char*)HexBuf, i = 0; i < HexLen; i++, p++){
      c = *AscBuf++;
      if ( c == ' ' )
         c = '0';
      if ( c >= '0' && c <= '9' )
         *p = (c - '0') * 16;
      else if ( c >= 'a' && c <= 'z' )
         *p = (c - 'a' + 10) * 16;
      else
         *p = (c - 'A' + 10) * 16;
      c = *AscBuf++;
      if ( c == ' ' )
         c = '0';
      if ( c >= '0' && c <= '9' )
         *p += c - '0';
      else if ( c >= 'a' && c <= 'z' )
         *p += c - 'a' + 10;
      else
         *p += c - 'A' + 10;
   }
}

long BkRandom(void)
{
   return random();
}

void BkRandomize(void)
{
   srandom(time(NULL));
}

void BkMemDump(FILE *f, const void *p, size_t len)
{
   size_t i;
   const unsigned char *s;
   char TmpStr[500 + 1], AsciiStr[17];
   int Pos = 0;

   BK_ASSERT( f != NULL && p != NULL );
   AsciiStr[16] = BK_EOS;

   for ( i = 0, s = (const unsigned char *)p; ; i++, s++)
   {
      if ( i % 16 == 0 )
      {
         if ( i >= len )
         {
            break;
         }
         snprintf(TmpStr, 500, "%08x  ", i);
         Pos = 10;
      }
      if ( i % 16 == 8 )
      {
         TmpStr[Pos++] = ' ';
      }
      if ( i >= len )
      {
         AsciiStr[i % 16] = ' ';
         memset(TmpStr + Pos, ' ', 3);
         Pos += 3;
      }
      else
      {
         if ( *s > 126 || *s < ' ' )
         {
            AsciiStr[i % 16] = '.';
         }
         else
         {
            AsciiStr[i % 16] = *s;
         }
         snprintf(TmpStr + Pos, 500 - Pos, " %02x", *s);
         Pos += 3;
      }
      if ( i % 16 == 15 )
      {
         TmpStr[Pos] = '\0';
         fprintf(f, "%s   %s\n", TmpStr, AsciiStr);
      }
   }
}

int BkReadLine(FILE *f, char *s, int MaxLen)
{
   int i, c;

   BK_ASSERT( f != NULL && s != NULL && MaxLen > 0 );

   for ( i = 0; i < MaxLen;){
      c = fgetc(f);
      if ( c == BK_TAB || c == '\r' || c == 0x1a )
         c = ' ';
      if ( c == EOF || c == BK_NEWLINE )
         break;
      s[i++] = c;
      if ( c == BK_NEWPAGE )
         break;
   }

   s[i] = BK_EOS;

   if ( i == MaxLen )
      for ( ;;){
         c = fgetc(f);
         if ( c == EOF || c == BK_NEWLINE )
            break;
      }

   if ( c == EOF && i == 0 )
      return -1;
   else
      return i;
}

int BkReadWord(const char *s, char *w,
   const char *separators, int MaxLen)
{
   int i, j;

   BK_ASSERT( s != NULL && w != NULL && separators != NULL && MaxLen > 0 );

   i = 0;

   if ( strchr(separators, ' ') )
      for ( ; s[i] == ' '; i++)
         ;

   j = 0;

   if ( s[i] == BK_EOS ){
      w[0] = BK_EOS;
      return 0;
   }

   if ( strchr(separators, s[i]) )
      w[j++] = s[i++];
   else
      for ( ; j < MaxLen && !strchr(separators, s[i]) &&
            s[i] != BK_EOS; i++, j++)
         w[j] = s[i];

   w[j] = BK_EOS;
   return i;
}

int BkProcInfoStartBrow(BK_PROC_INFO *p)
{
   char TmpStr[500 + 1];
   int i;

   BK_ASSERT( p != NULL );
   BK_ASSERT( BkTmpDir[0] != BK_EOS );

   snprintf(TmpStr, 500, "%s > %s/procinfo.%u", BK_PS_STRING, BkTmpDir,
      (unsigned int)getpid());
   system(TmpStr);
   snprintf(TmpStr, 500, "%s/procinfo.%u", BkTmpDir, (unsigned int)getpid());

   if ( (p->f = fopen(TmpStr, "rt")) == NULL )
      return -1;

   for ( i=0; ; i++)
      if ( BkReadLine(p->f, TmpStr, 500) == -1 )
         break;

   fseek(p->f, 0, SEEK_SET);
   (void)BkReadLine(p->f, TmpStr, 500);
   return i - 1;
}

int BkProcInfoReadNext(BK_PROC_INFO *p)
{
   char s[501], w[501];
   int r;

   BK_ASSERT( p != NULL && p->f != NULL );

   if ( p->f == NULL )
      return -1;

   if ( BkReadLine(p->f, s, 500) == -1 )
      return -1;

   r = 0;
   r += BkReadWord(s + r, w, " ", 500);
   p->uid = (uid_t)atoi(w);
   r += BkReadWord(s + r, w, " ", 500);
   p->pid = (pid_t)atoi(w);
   r += BkReadWord(s + r, w, " ", 500);
   w[32] = BK_EOS;
   BkStrNCpy(p->name, w, sizeof(p->name) - 1);
   r += BkReadWord(s + r, w, " ", 500);
   BkStrNCpy(p->argv0, w, sizeof(p->argv0) - 1);
   r += BkReadWord(s + r, w, " ", 500);
   BkStrNCpy(p->argv1, w, sizeof(p->argv1) - 1);
   return 0;
}

void BkProcInfoEndBrow(BK_PROC_INFO *p)
{
   char TmpStr[500 + 1];

   BK_ASSERT( p != NULL && p->f != NULL );
   BK_ASSERT( BkTmpDir[0] != BK_EOS );

   if ( p->f == NULL )
      return;

   fclose(p->f);
   p->f = NULL;
   snprintf(TmpStr, 500, "%s/procinfo.%u", BkTmpDir, (unsigned int)getpid());
   unlink(TmpStr);
}

int BkDbfStartBrow(const char *FileName, BK_DBF_INFO *p)
{
   char buf[32];

   BK_ASSERT( !BkIsEmptyString(FileName) && p != NULL );

   if ( (p->f = fopen(FileName, "rb")) == NULL )
      return -1;

   fread(buf, 32, 1, p->f);

   if ( buf[0] != 0x03 || buf[1] != 0x63 ){
      fclose(p->f);
      p->f = NULL;
      return -1;
   }

   p->RecSize = buf[10] + buf[11] * 256;
   fseek(p->f, buf[8] + buf[9] * 256, SEEK_SET);
   return buf[4] + buf[5] * 256;
}

int BkDbfReadNext(BK_DBF_INFO *p)
{
   BK_ASSERT( p != NULL && p->f != NULL && p->buf != NULL );

   for ( ;;){
      if ( fread(p->buf, p->RecSize, 1, p->f) != 1 )
         return -1;
      if ( p->buf[0] == ' ' )
         return 0;
   }
}

void BkDbfEndBrow(BK_DBF_INFO *p)
{
   BK_ASSERT( p != NULL && p->f != NULL );

   fclose(p->f);
   p->f = NULL;
}

int BkGetDbfFieldsInfo(const char *FileName, BK_DBF_FIELDS_INFO *p)
{
   FILE *f;
   char buf[32];
   int i;

   BK_ASSERT( !BkIsEmptyString(FileName) && p != NULL );

   if ( (f = fopen(FileName, "rb")) == NULL )
      return -1;

   fread(buf, 32, 1, f);
   p->n = ((unsigned int)buf[8] + (unsigned int)buf[9] * 256 - 33) / 32;

   if ( buf[0] != 0x03 || buf[1] != 0x63 ){
      fclose(f);
      return -1;
   }

   for ( p->DbfRecLen = 1, p->StructLen = 0, i = 0; i < p->n; i++){
      fread(buf, 32, 1, f);
      memcpy(p->name[i], buf, 21);
      p->len[i]= buf[16] + buf[17] * 256;
      p->DbfRecLen += p->len[i];
      p->StructLen += p->len[i] + 1;
      p->type[i] = buf[11];
   }

   fclose(f);
   return 0;
}

void BkCopyDbfrecToStruct(BK_DBF_FIELDS_INFO *p, char *RecP, char *StructP)
{
   int i;

   BK_ASSERT( p != NULL && RecP != NULL && StructP != NULL );

   for ( RecP++, i = 0; i < p->n; i++){
      memcpy(StructP, RecP, p->len[i]);
      StructP[p->len[i]] = BK_EOS;
      BkRightTrim(StructP);
      StructP += p->len[i] + 1;
      RecP += p->len[i];
   }
}

void BkCopyStructToDbfrec(BK_DBF_FIELDS_INFO *p, char *RecP, char *StructP)
{
   size_t len;
   int i;

   BK_ASSERT( p != NULL && RecP != NULL && StructP != NULL );

   for ( *RecP++ = ' ', i = 0; i < p->n; i++){
      len = strlen(StructP);
      if ( len > p->len[i] )
         memcpy(RecP, StructP, p->len[i]);
      else{
         memset(RecP, ' ', p->len[i]);
         memcpy(RecP, StructP, len);
      }
      StructP += p->len[i] + 1;
      RecP += p->len[i];
   }
}

int BkCountLine(const char *s)
{
   int i;

   BK_ASSERT( s != NULL );

   for ( i = 1; *s != BK_EOS; s++)
      if ( *s == BK_NEWLINE )
         i++;

   return i;
}

char *BkTheNthString(BK_STRING_LIST *sl, int n)
{
   BK_STRING_LIST *p;
   int i;

   BK_ASSERT( sl != NULL && n >= 0 );

   for ( p = sl, i = 0; i < n; i++, p = p->next);

   return p->s;
}

int BkFindStringInString(const char *s, int *x,
   const char *pattern, int direction, int *len)
{
   const char *p, *p2, *p3;

   BK_ASSERT( s != NULL && x != NULL && !BkIsEmptyString(pattern) );
   BK_ASSERT( len != NULL && *x >= 0 );
   BK_ASSERT( direction == BK_FIND_DIRECT_NEXT ||
      direction == BK_FIND_DIRECT_PREVIOUS );

   *len = strlen(pattern);

   for ( p = NULL, p3 = s;;){
      p2 = strstr(p3, pattern);

      if ( direction == BK_FIND_DIRECT_NEXT ){
         if ( p2 == NULL )
            return 1;
         if ( p2 - s >= *x ){
            *x = p2 - s;
            return 0;
         }
      }
      else
         if ( p2 == NULL || p2 - s >= *x )
            if ( p == NULL )
               return 1;
            else{
               *x = p - s;
               return 0;
            }

      p  = p2;
      p3 = p2 + *len;
   }
}

int BkExecCommand(const char *command,
   const char *ResultFile, char **envs)
{
   FILE *f;
   int fd, r;
   char ShellFileName[500 + 1];
   pid_t pid;
   void (*OldAction)(int);

   BK_ASSERT( !BkIsEmptyString(command) );
   BK_ASSERT( !BkIsEmptyString(BkTmpDir) );

   snprintf(ShellFileName, 500, "%s/bksh.%u", BkTmpDir, (unsigned int)getpid());
   f = fopen(ShellFileName, "wt");

   if ( f == NULL )
      return -1;

   fprintf(f, "%s", command);
   fclose(f);
   OldAction = BkSignal(SIGCHLD, SIG_DFL, 0);

   if ( ResultFile != NULL ){
      fd = open(ResultFile, O_CREAT | O_WRONLY, 0600);
      if ( fd == -1 )
         return -1;
   }

   pid = fork();

   if ( pid == -1 ){
      close(fd);
      BkSignal(SIGCHLD, OldAction, 0);
      unlink(ShellFileName);
      return -1;
   }

   if ( pid == 0 ){
      if ( ResultFile != NULL ){
         close(1);
         close(2);
         dup(fd);
         dup(fd);
      }
      if ( envs == NULL )
         execl("/bin/sh", "", ShellFileName, NULL);
      else
         execle("/bin/sh", "", ShellFileName, NULL, envs);
      exit(-1);
   }

   r = -1;
   waitpid(pid, &r, 0);

   if ( ResultFile != NULL )
      close(fd);

   BkSignal(SIGCHLD, OldAction, 0);
   unlink(ShellFileName);

   if ( WIFEXITED(r) )
      return WEXITSTATUS(r);
   else
      return -1;
}

void BkStrNCpy(char *s1, const char *s2, size_t len)
{
   size_t i;

   BK_ASSERT( s1 != NULL && s2 != NULL );

   for ( i = 0; i < len && *s2 != BK_EOS; i++)
      *s1++ = *s2++;

   *s1 = '\0';
}

void BkLocalTime(time_t *t, struct tm *tm)
{
   BK_ASSERT( t != NULL && tm != NULL );

   #ifdef _REENTRANT
      localtime_r(t, tm);
   #else
      memcpy(tm, localtime(t), sizeof(struct tm));
   #endif
}

void BkDateCompute(char *NewDate, const char *OldDate, int Days)
{
   char TmpStr[500 + 1];
   struct tm tm;
   int n;
   time_t t;

   memcpy(TmpStr, OldDate, 4);
   TmpStr[4] = '\0';
   n = BkStrToInt(TmpStr);
   tm.tm_year = n - 1900;

   memcpy(TmpStr, OldDate + 4, 2);
   TmpStr[2] = '\0';
   n = BkStrToInt(TmpStr);
   tm.tm_mon = n - 1;

   memcpy(TmpStr, OldDate + 4 + 2, 2);
   TmpStr[2] = '\0';
   n = BkStrToInt(TmpStr);
   tm.tm_mday = n;

   tm.tm_hour = 0;
   tm.tm_min = 0;
   tm.tm_sec = 0;
   tm.tm_isdst = -1;

   t = mktime(&tm);
   t += Days * 24 * 60 * 60;
   BkLocalTime(&t, &tm);
   snprintf(TmpStr, 500, "%04d%02d%02d", tm.tm_year + 1900,
      tm.tm_mon + 1, tm.tm_mday);
   memcpy(NewDate, TmpStr, 8);
}

void BkToday(char *s)
{
   time_t     t;
   struct tm  tm;

   BK_ASSERT( s != NULL );

   t = time(NULL);
   BkLocalTime(&t, &tm);
   snprintf(s, 8 + 1, "%4d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
}

void BkCurrTime(char *s)
{
   time_t     t;
   struct tm  tm;

   BK_ASSERT( s != NULL );

   t = time(NULL);
   BkLocalTime(&t, &tm);
   snprintf(s, 14 + 1, "%4d%02d%02d%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
      tm.tm_hour, tm.tm_min, tm.tm_sec);
}

static void TeaEncrypt64Bits(BK_UINT32 *v, const BK_UINT32 *k);
static void TeaDecrypt64Bits(BK_UINT32 *v, const BK_UINT32 *k);

static void TeaEncrypt64Bits(BK_UINT32 *v, const BK_UINT32 *k)
{
   BK_UINT32 y, z, sum, delta, a, b, c, d;
   int n;

   sum   = 0;
   delta = 0x9e3779b9UL;
   y     = Bkntohl(v[0]);
   z     = Bkntohl(v[1]);
   a     = Bkntohl(k[0]);
   b     = Bkntohl(k[1]);
   c     = Bkntohl(k[2]);
   d     = Bkntohl(k[3]);

   for ( n = 32; n > 0; n--){
      sum += delta;
      y += (z << 4) + (a ^ z) + (sum ^ (z >> 5)) + b;
      z += (y << 4) + (c ^ y) + (sum ^ (y >> 5)) + d;
   }

   v[0] = Bkhtonl(y);
   v[1] = Bkhtonl(z);
}

static void TeaDecrypt64Bits(BK_UINT32 *v, const BK_UINT32 *k)
{
   BK_UINT32 y, z, sum, delta, a, b, c, d;
   int n;

   sum   = 0xc6ef3720UL;
   delta = 0x9e3779b9UL;
   y     = Bkntohl(v[0]);
   z     = Bkntohl(v[1]);
   a     = Bkntohl(k[0]);
   b     = Bkntohl(k[1]);
   c     = Bkntohl(k[2]);
   d     = Bkntohl(k[3]);

   for ( n = 32; n > 0; n--){
      z -= (y << 4) + (c ^ y) + (sum ^ (y >> 5)) + d;
      y -= (z << 4) + (a ^ z) + (sum ^ (z >> 5)) + b;
      sum -= delta;
   }

   v[0] = Bkhtonl(y);
   v[1] = Bkhtonl(z);
}

void BkTeaEncrypt(void *buf, const void *key, size_t len)
{
   BK_UINT32 k[4], v[2];
   char *p;
   ssize_t i;

   BK_ASSERT( buf != NULL && key != NULL );

   p = (char*)buf;
   memcpy(k, key, 16);

   for ( i = len / 8; i > 0; i--){
      memcpy(v, p, 8);
      TeaEncrypt64Bits(v, k);
      memcpy(p, v, 8);
      p += 8;
   }
}

void BkTeaDecrypt(void *buf, const void *key, size_t len)
{
   BK_UINT32 k[4], v[2];
   char *p;
   ssize_t i;

   BK_ASSERT( buf != NULL && key != NULL );

   p = (char*)buf;
   memcpy(k, key, 16);

   for ( i = len / 8; i > 0; i--){
      memcpy(v, p, 8);
      TeaDecrypt64Bits(v, k);
      memcpy(p, v, 8);
      p += 8;
   }
}

void BkTeaEncryptString(const char *StringIn,
   char *StringOut, const void *k)
{
   char s[8 + 1];
   long len;

   BK_ASSERT( StringIn != NULL && StringOut != NULL && k != NULL );

   for ( len = strlen(StringIn); len > 0; len -= 8){
      BK_CLEAR(s);
      BkStrNCpy(s, StringIn, 8);
      BkTeaEncrypt(s, k, 8);
      BkHexToAsc(s, StringOut, 8);
      StringIn += 8;
      StringOut += 16;
   }

   *StringOut = BK_EOS;
}

void BkTeaDecryptString(const char *StringIn,
   char *StringOut, const void *k)
{
   long len;

   BK_ASSERT( StringIn != NULL && StringOut != NULL && k != NULL );

   for ( len = strlen(StringIn); len > 0; len -= 16){
      BkAscToHex(StringOut, StringIn, 8);
      BkTeaDecrypt(StringOut, k, 8);
      StringIn += 16;
      StringOut += 8;
   }

   *StringOut = BK_EOS;
}

void BkSimpleCheck(const char *buf, char sum[8], size_t len)
{
   ssize_t i;
   int j;

   BK_ASSERT( buf != NULL && len > 7 );

   for ( i = 0; i < 8; i++)
      sum[i] = 0;

   for ( i = len / 8; i > 0; i--)
      for ( j = 0; j < 8; j++)
         sum[j] ^= *buf++;
}

#define MASK_C  0x01
#define MASK_S  0x02
#define MASK_Z  0x04

void BkVm(char *mem, char **ext, int pc)
{
   unsigned int op1, op2, op3;
   int flags;
   int i, StackP;
   unsigned char c;
   char bow, stack[2048];
   static char ByteOrWord[48]={
      0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
      0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
      0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10,
      0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   };
   time_t StartTime, t;

   flags = 0;
   StackP = 0;
   StartTime = time(NULL);

   for ( ;;){
      c = mem[pc++];
      if ( ( c & 0xe0 ) == 0x20 )
         bow = ByteOrWord[c & 0x0f];
      if ( ( c & 0xc0 ) == 0x40 )
         bow = ByteOrWord[(c & 0x0f) + 16];
      if ( ( c & 0x80 ) == 0x80 )
         bow = ByteOrWord[(c & 0x0f) + 32];
      if ( ( c & 0xe0 ) != 0x00 ){
         op1 = mem[pc++];
         if ( ( c & 0x10 ) || ( bow & 0x10 ) )
            op1 = op1 + mem[pc++] * 256;
         if ( c & 0x10 )
            if ( bow & 0x10 )
               op1 = mem[op1] + mem[op1 + 1] * 256;
            else
               op1 = mem[op1];
         c &= ~0x10;
      }
      if ( ( c & 0xc0 ) != 0x00 ){
         op2 = mem[pc++];
         if ( ( c & 0x20 ) || ( bow & 0x20 ) )
            op2 = op2 + mem[pc++] * 256;
         if ( c & 0x20 )
            if ( bow & 0x20 )
               op2 = mem[op2] + mem[op2 + 1] * 256;
            else
               op2 = mem[op2];
         c &= ~0x20;
      }
      if ( ( c & 0x80 ) != 0x00 ){
         op3 = mem[pc++];
         if ( ( c & 0x40 ) || ( bow & 0x40 ) )
            op3 = op3 + mem[pc++] * 256;
         if ( c & 0x40 )
            if ( bow & 0x40 )
               op3 = mem[op3] + mem[op3 + 1] * 256;
            else
               op3 = mem[op3];
         c &= ~0x40;
      }
      switch(c){
      case 0x01 :
         if ( StackP == 0 )
            return;
         pc = stack[StackP - 1] * 256 + stack[StackP - 2];
         StackP -= 2;
         break;
      case 0x02 :
         break;
      case 0x03 :
         flags |= MASK_C;
         break;
      case 0x04 :
         flags &= ~MASK_C;
         break;
      case 0x05 :
         flags |= MASK_S;
         break;
      case 0x06 :
         flags &= ~MASK_S;
         break;
      case 0x07 :
         flags |= MASK_Z;
         break;
      case 0x08 :
         flags &= ~MASK_Z;
         break;
      case 0x09 :
         stack[StackP++] = flags % 256;
         break;
      case 0x0a :
         flags = stack[--StackP];
         break;
      case 0x20 :
         pc = op1;
         break;
      case 0x21 :
         if ( (flags & MASK_C) != 0 )
            if ( op1 >= 128 )
               pc += op1 - 256;
            else
               pc += op1;
         break;
      case 0x22 :
         if ( (flags & MASK_C) == 0 )
            if ( op1 >= 128 )
               pc += op1 - 256;
            else
               pc += op1;
         break;
      case 0x23 :
         if ( (flags & MASK_S) != 0 )
            if ( op1 >= 128 )
               pc += op1 - 256;
            else
               pc += op1;
         break;
      case 0x24 :
         if ( (flags & MASK_S) == 0 )
            if ( op1 >= 128 )
               pc += op1 - 256;
            else
               pc += op1;
         break;
      case 0x25 :
         if ( (flags & MASK_Z) != 0 )
            if ( op1 >= 128 )
               pc += op1 - 256;
            else
               pc += op1;
         break;
      case 0x26 :
         if ( (flags & MASK_Z) == 0 )
            if ( op1 >= 128 )
               pc += op1 - 256;
            else
               pc += op1;
         break;
      case 0x27 :
         stack[StackP++] = mem[op1];
         break;
      case 0x28 :
         mem[op1] = stack[--StackP];
         break;
      case 0x29 :
         stack[StackP++] = pc % 256;
         stack[StackP++] = pc / 256;
         pc = op1;
         break;
      case 0x2a :
         if ( (flags & MASK_C) == 0 ){
            if ( (mem[op1] & 0x80) == 0 )
               flags |= MASK_C;
            else
               flags &= ~MASK_C;
            mem[op1] <<= 1;
         }
         else{
            if ( (mem[op1] & 0x80) == 0 )
               flags |= MASK_C;
            else
               flags &= ~MASK_C;
            mem[op1] <<= 1;
            mem[op1] |= 0x01;
         }
         break;
      case 0x2b :
         if ( (flags & MASK_C) == 0 ){
            if ( (mem[op1] & 0x01) == 0 )
               flags |= MASK_C;
            else
               flags &= ~MASK_C;
            mem[op1] >>= 1;
         }
         else{
            if ( (mem[op1] & 0x01) == 0 )
               flags |= MASK_C;
            else
               flags &= ~MASK_C;
            mem[op1] >>= 1;
            mem[op1] |= 0x80;
         }
         break;
      case 0x2c :
         t = time(NULL) - StartTime;
         mem[op1] = t % 256;
         mem[op1 + 1] = t % 65536 / 256;
         break;
      case 0x40 :
         mem[op1] = op2 % 256;
         break;
      case 0x41 :
         if ( (flags & MASK_C) == 0 )
            i = (unsigned int)mem[op1] + (unsigned int)op2;
         else
            i = (unsigned int)mem[op1] + (unsigned int)op2 + 1;
         if ( i >= 256 ){
            mem[op1] = i - 256;
            flags |= MASK_C;
         }
         else{
            mem[op1] = i % 256;
            flags &= ~MASK_C;
         }
         if ( (mem[op1] & 0x80) != 0 )
            flags |= MASK_S;
         else
            flags &= ~MASK_S;
         if ( mem[op1] == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x42 :
         if ( (flags & MASK_C) == 0 )
            i = (unsigned int)mem[op1] - (unsigned int)op2;
         else
            i = (unsigned int)mem[op1] - (unsigned int)op2 - 1;
         if ( i < 0 ){
            mem[op1] = i + 256;
            flags |= MASK_C;
         }
         else{
            mem[op1] = i % 256;
            flags &= ~MASK_C;
         }
         if ( (mem[op1] & 0x80) != 0 )
            flags |= MASK_S;
         else
            flags &= ~MASK_S;
         if ( mem[op1] == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x43 :
         mem[op1] = mem[op1] & (op2 % 256);
         if ( (mem[op1] & 0x80) != 0 )
            flags |= MASK_S;
         else
            flags &= ~MASK_S;
         if ( mem[op1] == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x44 :
         mem[op1] = mem[op1] | (op2 % 256);
         if ( (mem[op1] & 0x80) != 0 )
            flags |= MASK_S;
         else
            flags &= ~MASK_S;
         if ( mem[op1] == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x45 :
         mem[op1] = mem[op1] ^ (op2 % 256);
         if ( (mem[op1] & 0x80) != 0 )
            flags |= MASK_S;
         else
            flags &= ~MASK_S;
         if ( mem[op1] == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x46 :
         i = (unsigned int)mem[op1] - (unsigned int)op2;
         if ( i < 0 ){
            i += 256;
            flags |= MASK_C;
         }
         else
            flags &= ~MASK_C;
         if ( (i & 0x80) != 0 )
            flags |= MASK_S;
         else
            flags &= ~MASK_S;
         if ( i == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x47 :
         for ( i = 0; i < op2; i++)
            mem[op1 + i] = BkRandom() % 256;
         break;
      case 0x48 :
         BkMemDump(stdout, mem + op1, op2);
         break;
      case 0x80 :
         memcpy(mem + op2, ext[op1], op3);
         break;
      case 0x81 :
         memcpy(ext[op1], mem + op2, op3);
         break;
      case 0x82 :
         memcpy(mem + op1, mem + op2, op3);
         break;
      case 0x83 :
         if ( memcmp(mem + op1, mem + op2, op3) == 0 )
            flags |= MASK_Z;
         else
            flags &= ~MASK_Z;
         break;
      case 0x84 :
         BkTeaEncrypt(mem + op1, mem + op2, op3);
         break;
      case 0x85 :
         BkTeaDecrypt(mem + op1, mem + op2, op3);
         break;
      default :
         break;
      }
   }
}

int BkMalloc(void *p, size_t size)
{
   char *TmpP;

   BK_ASSERT(p != NULL);
   TmpP = (char*)malloc(size + 1);

   #ifdef BK_DEBUG
      if ( TmpP != NULL ){
         memset(TmpP, MallocGarbage, size);
         TmpP[size] = TailChar;
         if ( !CreateBlockInfo(TmpP, size) ){
            free(TmpP);
            TmpP = NULL;
         }
      }
   #endif

   memcpy(p, &TmpP, sizeof(void*));

   if ( TmpP == NULL )
      return -1;
   else
      return 0;
}

void *BkMallocOldStyle(size_t size)
{
   char *TmpP;

   TmpP = (char*)malloc(size + 1);

   #ifdef BK_DEBUG
      if ( TmpP != NULL ){
         memset(TmpP, MallocGarbage, size);
         TmpP[size] = TailChar;
         if ( !CreateBlockInfo(TmpP, size) ){
            free(TmpP);
            TmpP = NULL;
         }
      }
   #endif

   return TmpP;
}

int BkRealloc(void *p, size_t size)
{
   char *TmpP;

   BK_ASSERT( p != NULL && size != 0 );

   #ifdef BK_DEBUG
   {
      size_t OldSize;
      void *NewBuffer;
      memcpy(&TmpP, p, sizeof(void*));
      OldSize = SizeOfBlock(TmpP);
      if ( size <= OldSize ){
         memset(TmpP + size + 1, FreeGarbage, OldSize - size);
         TmpP[size] = TailChar;
         UpdateBlockInfo(TmpP, TmpP, size);
      }
      if ( size > OldSize ){
         if ( BkMalloc(&NewBuffer, size) == 0 ){
            memcpy(NewBuffer, TmpP, OldSize);
            BkFree(TmpP);
            TmpP = NewBuffer;
            memcpy(p, &TmpP, sizeof(void*));
         }
      }
   }
   #endif

   memcpy(&TmpP, p, sizeof(void*));
   TmpP = (char*)realloc(TmpP, size + 1);

   if ( TmpP != NULL ){
      memcpy(p, &TmpP, sizeof(void*));
      return 0;
   }
   else
      return -1;
}

void *BkReallocOldStyle(void *p, size_t size)
{
   char *TmpP;

   BK_ASSERT( size != 0 );

   #ifdef BK_DEBUG
   {
      size_t OldSize;
      void *NewBuffer;
      TmpP = p;
      OldSize = SizeOfBlock(TmpP);
      if ( size <= OldSize ){
         memset(TmpP + size + 1, FreeGarbage, OldSize - size);
         TmpP[size] = TailChar;
         UpdateBlockInfo(TmpP, TmpP, size);
      }
      if ( size > OldSize ){
         if ( BkMalloc(&NewBuffer, size) == 0 ){
            memcpy(NewBuffer, TmpP, OldSize);
            BkFree(TmpP);
            p = NewBuffer;
         }
      }
   }
   #endif

   p = realloc(p, size + 1);
   return p;
}

void BkFree(void *p)
{
   #ifdef BK_DEBUG
   {
      size_t size;
      BK_ASSERT( p != NULL );
      size = SizeOfBlock(p);
      /* 每次 BkMalloc 都多分配一个字节并且将其置为 TailChar */
      /* 如果这个字节的值改变了，说明曾经有内存击穿发生 */
      BK_ASSERT( *((char*)p + size) == TailChar );
      memset(p, FreeGarbage, size);
      FreeBlockInfo(p);
   }
   #endif
   free(p);
}

void BkCheckLostMemory(void)
{
   BK_ASSERT( head == NULL );
}

void BkCatNChars(char *s, size_t n, char c)
{
   size_t i;

   BK_ASSERT( s != NULL );

   for ( ; *s != BK_EOS; s++);

   for ( i = 0; i < n; i++)
      *s++ = c;

   *s = BK_EOS;
}

static void AmtCat(char *AmtStr, const char *s, size_t len, size_t *CurLen,
   size_t MaxLen)
{
   if ( MaxLen % 2 != 0 )
      MaxLen--;

   if ( *CurLen == MaxLen )
      return;

   if ( len + *CurLen > MaxLen ){
      memcpy(AmtStr + *CurLen, s, MaxLen - *CurLen);
      *CurLen = MaxLen;
   }
   else{
      memcpy(AmtStr + *CurLen, s, len);
      *CurLen += len;
   }
}

void BkCapAmt(double amt, char *AmtStr, int MaxLen)
{
   static const char *text1 = "壹贰叁肆伍陆柒捌玖";
   static const char *text2 = "拾万仟佰拾亿仟佰拾万仟佰拾元";
   char TmpStr[500 + 1];
   int i, j, flag;
   size_t CurLen;

   BK_ASSERT( amt >= 0 && amt < 1e15 && AmtStr != NULL && MaxLen > 0 );

   memset(AmtStr, ' ', MaxLen);
   AmtStr[MaxLen] = BK_EOS;

   CurLen = 0;
   snprintf(TmpStr, 500, "%017.2f", amt);

   if ( memcmp(TmpStr, "00000000000000.00", 17) == 0 ){
      AmtCat(AmtStr, "零元整", 6, &CurLen, MaxLen);
      return;
   }

   if ( memcmp(TmpStr, "00000000000000", 14) != 0 ){
      for ( j = 0, flag = 1, i = 0; i < 14; i++){
         if ( flag == 1 && TmpStr[i] == '0' )
            continue;
         flag = 0;
         if ( TmpStr[i] != '0' ){
            if ( j > 0 ){
               AmtCat(AmtStr, "零", 2, &CurLen, MaxLen);
               j = 0;
            }
            AmtCat(AmtStr, text1 + ( TmpStr[i] - '1' ) * 2, 2, &CurLen, MaxLen);
            AmtCat(AmtStr, text2 + i * 2, 2, &CurLen, MaxLen);
         }
         else{
            if ( i == 1 || i == 5 || i == 13 || ( i == 9 && j < 3 ) )
               AmtCat(AmtStr, text2 + i * 2, 2, &CurLen, MaxLen);
            j++;
         }
      }
   }

   i = 15;

   if ( TmpStr[i] != '0' ){
      AmtCat(AmtStr, text1 + ( TmpStr[i] - '1') * 2, 2, &CurLen, MaxLen);
      AmtCat(AmtStr, "角", 2, &CurLen, MaxLen);
   }

   i++;

   if ( TmpStr[i] != '0' ){
      AmtCat(AmtStr, text1 + ( TmpStr[i] - '1' ) * 2, 2, &CurLen, MaxLen);
      AmtCat(AmtStr, "分", 2, &CurLen, MaxLen);
   }
   else
      AmtCat(AmtStr, "整", 2, &CurLen, MaxLen);
}

int BkStringIsAll(const char *s, char c)
{
   size_t i;
   int flag;

   BK_ASSERT( s != NULL );

   for ( i = 0, flag = 1; s[i] != BK_EOS; i++)
      if ( s[i] != c ){
         flag = 0;
         break;
      }

   return flag;
}

void BkFormatString(const char *src, char *des,
   const char *fmt, int BlankWhenZero)
{
   size_t i, j;
   int flag;

   BK_ASSERT( src != NULL && des != NULL && fmt != NULL );

   if ( BlankWhenZero ){
      for ( flag = 0, i = 0; src[i] != BK_EOS && fmt[i] != BK_EOS; i++)
         if ( src[i] != '0' ){
            flag = 1;
            break;
         }
      if ( flag != 0 ){
         memset(des, ' ', strlen(fmt));
         des[strlen(fmt)] = BK_EOS;
         return;
      }
      for ( flag = 0, i = 0; src[i] != BK_EOS && fmt[i] != BK_EOS; i++)
         if ( src[i] != ' ' ){
            flag = 1;
            break;
         }
      if ( flag != 0 ){
         memset(des, ' ', strlen(fmt));
         des[strlen(fmt)] = BK_EOS;
         return;
      }
   }

   for ( i = 0, j = 0, flag = 0; fmt[i] != BK_EOS; i++){
      if ( fmt[i] != 'n' ){
         des[i] = fmt[i];
         continue;
      }
      if ( flag == 0 )
          if ( src[j] == BK_EOS ){
             des[i] = ' ';
             flag = 1;
          }
          else
             des[i] = src[j++];
      else
         des[i] = ' ';
   }

   des[i] = BK_EOS;
}

void BkFormatDouble(double d, char *des,
   const char *fmt, int BlankWhenZero)
{
   int i, j, sign, width, precision;
   char c, TmpStr[501];

   BK_ASSERT( des != NULL );
   BK_ASSERT( fmt[0] == 'z' || fmt[0] == '*' || fmt[0] == '$' ||
      fmt[0] == '-' || fmt[0] == '+' );

   memset(des, ' ', strlen(fmt));
   des[strlen(fmt)] = BK_EOS;

   if ( BlankWhenZero && d < 0.0000001 && d > -0.00000001 )
      return;

   if ( d < 0 ){
      sign = -1;
      d = -d;
   }
   else
      sign = 1;

   for ( width = 0, precision = 0, i = 0; fmt[i] != BK_EOS; i++){
      if ( fmt[i] == ',' )
         continue;
      if ( fmt[i] == '.' ){
         precision = 0;
         continue;
      }
      width++;
      precision++;
   }

   if ( width == precision )
      precision = 0;
   else
      width++;

   snprintf(TmpStr, 500, "%0*.*f", width, precision, d);
   c = fmt[0];

   if ( fmt[0] == '-' && sign == 1 )
      c = ' ';

   if ( fmt[0] == '+' && sign == -1 )
      c = '-';

   for ( i = 0, j = 0;;){
      if ( fmt[i] == ',' ){
         if ( fmt[0] == '*' )
            des[i++] = '*';
         else
            des[i++] = ' ';
         continue;
      }
      if ( fmt[i] == 'n' || TmpStr[j] != '0' )
         break;
      if ( fmt[0] == '*' )
         des[i++] = '*';
      else
         des[i++] = ' ';
      j++;
   }

   if ( fmt[0] != 'z' && fmt[0] != '*' && i > 0 )
      des[i - 1] = c;

   for ( ; fmt[i] != BK_EOS; i++){
      if ( fmt[i] == '.' ){
         des[i] = '.';
         j++;
         continue;
      }
      if ( fmt[i] == ',' ){
         des[i] = ',';
         continue;
      }
      des[i] = TmpStr[j++];
   }

   des[i] = BK_EOS;
}

void BkLeftAligned(char *s, size_t len)
{
   size_t i, j;

   BK_ASSERT( s != NULL );

   for ( i = 0; s[i] == ' ' && i < len; i++);

   for ( j = 0; s[i] != BK_EOS && i < len; i++, j++)
      s[j] = s[i];

   memset(s + j, ' ', len - j);
   s[len] = BK_EOS;
}

void BkRightAligned(char *s, size_t len)
{
   size_t i, j;

   BK_ASSERT( s != NULL && (int)strlen(s) <= len);

   BkRightTrim(s);

   for ( i = 0; s[i] == ' '; i++);
   
   j = strlen(s + i);

   if ( j == len )
      return;

   if ( j == 0 ){
      memset(s, ' ', len);
      s[len] = BK_EOS;
      return;
   }

   memmove(s + len - i - j, s + i, len - i - j + 1);
   memset(s, ' ', len - j);
}

void BkWriteErrorLog(const char *FormatStr, ...)
{
   char         TmpStr[1024 + 1];
   va_list      VaList;
   int          fd;
   time_t       t;
   struct tm    tm;
   int Len = 0;

   BK_ASSERT( FormatStr != NULL );

   if ( BkIsEmptyString(ErrorLogFileName) )
      return;

   fd = open(ErrorLogFileName, O_CREAT | O_WRONLY | O_APPEND, 0600);

   if ( fd == -1 )
      return;

   t = time(NULL);
   BkLocalTime(&t, &tm);
   Len = snprintf(TmpStr, 1024, "%04d/%02d/%02d %02d:%02d:%02d  ",
      1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
      tm.tm_hour, tm.tm_min, tm.tm_sec);
   va_start(VaList, FormatStr);
   Len += vsnprintf(TmpStr + Len, 1024 - Len, FormatStr, VaList);
   va_end(VaList);
   memcpy(TmpStr + Len, "\n", 2);
   write(fd, TmpStr, Len + 1);
   close(fd);
}

void BkPrintError(const char *FormatStr, ...)
{
   char         TmpStr[500 + 1];
   va_list      VaList;
   int          fd;
   struct tm    tm;
   struct timeb tp;

   BK_ASSERT( FormatStr != NULL );

   ftime(&tp);
   BkLocalTime(&tp.time, &tm);
   snprintf(TmpStr, 500, "%04d/%02d/%02d %02d:%02d:%02d.%03d(%10d)  ",
      1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
      tm.tm_hour, tm.tm_min, tm.tm_sec, tp.millitm, getpid());
   fprintf(stderr, "%s", TmpStr);
   va_start(VaList, FormatStr);
   vfprintf(stderr, FormatStr, VaList);
   va_end(VaList);
   fprintf(stderr, "\n");
}

void BkSetLogFile(const char *s)
{
   if (s == NULL)
      ErrorLogFileName[0] = '\0';
   else
      BkStrNCpy(ErrorLogFileName, s, sizeof(ErrorLogFileName) - 1);
}

int BkGetFsInfo(const char *path, BK_FS_INFO *p)
{
   struct statfs64 Stat;

   if ( statfs64((char*)path, &Stat) == -1 )
   {
      return -1;
   }

   int n = 1024 * 1024;

   for ( ; Stat.f_bsize % 2 == 0 && n > 1; )
   {
      Stat.f_bsize /= 2;
      n /= 2;
   }

   p->total_blocks = Stat.f_blocks * Stat.f_bsize / n;
   p->free_blocks = Stat.f_bfree * Stat.f_bsize / n;
   return 0;
}

void BkCpyAndAddEos(char *des, const void *src, size_t len)
{
   memcpy(des, src, len);
   des[len] = BK_EOS;
   BkRightTrim(des);
}

int BkSearchArrByKey(BK_ARRAY arr, const void *buf,
   int KeyOff, size_t KeyLen)
{
   int i, j, k, r, n;
   char *p;

   BK_ASSERT( arr.p != NULL && buf != NULL );

   if ( KeyOff == 0 ){ /* 键值从第一个字节开始的可以用二分法查找 */
      for ( n = -1, i = 0, j = arr.n - 1; i <= j; ){
         k = (i + j) / 2;
         p = arr.p + k * arr.size;
         r = memcmp(p + KeyOff, (char*)buf + KeyOff, KeyLen);
         if ( r == 0 )
            n = k;
         if ( r < 0 )
            i = k + 1;
         else
            j = k - 1;
      }
      return n;
   }
   else{ /* 顺序查找 */
      for ( p = arr.p, i = 0; i < arr.n; i++){
         if ( memcmp(p, buf, KeyLen) == 0 )
            break;
         p += arr.size;
      }
      if ( i == arr.n )
         return -1;
      return i;
   }
}

int BkReadArrByKey(BK_ARRAY arr, void *buf,
   int KeyOff, size_t KeyLen)
{
   int i;

   BK_ASSERT( arr.p != NULL && buf != NULL );

   i = BkSearchArrByKey(arr, buf, KeyOff, KeyLen);

   if ( i == -1 )
      return -1;

   memcpy(buf, arr.p + arr.size * i, arr.size);
   return 0;
}

int BkWriteArrByKey(BK_ARRAY arr, void *buf, int KeyOff, size_t KeyLen)
{
   int i;

   BK_ASSERT( arr.p != NULL && buf != NULL );

   i = BkSearchArrByKey(arr, buf, KeyOff, KeyLen);

   if ( i == -1 )
      return -1;

   memcpy(arr.p + arr.size * i, buf, arr.size);
   return 0;
}

void BkSortArr(BK_ARRAY arr)
{
   char *data;
   int i, j, k, min;

   BK_ASSERT( arr.p != NULL );

   (void)BkMalloc(&data, arr.size);

   for ( i = 0; i < arr.n - 1; i++){
      min = i;
      for ( j = i + 1; j < arr.n; j++)
         if ( memcmp(arr.p + arr.size * min,
                    arr.p + arr.size * j, arr.size) > 0 ){
            k = min;
            min = j;
            j = k;
         }
      memcpy(data, arr.p + arr.size * i, arr.size);
      memcpy(arr.p + arr.size * i, arr.p + arr.size * min, arr.size);
      memcpy(arr.p + arr.size * min, data, arr.size);
   }

   BkFree(data);
}

BK_HANDLER BkSignalIgnore(int signo)
{
   return BkSignal(signo, SIG_IGN, 0);
}

void BkChangeChar(char *s, const char *CharsToReplace, char c)
{
   for ( ; *s != BK_EOS; s++)
      if ( strchr(CharsToReplace, *s) != NULL )
         *s = c;
}

#define sift(ARG1, ARG2) \
   { \
      unsigned long i, j, K, M; \
      K = (ARG1); \
      M = (ARG2); \
      memcpy(tmp, data + size * ( K - 1 ), size); \
      for (  i = K, j = i * 2; j <= M; ){ \
         if ( j < M && f(data + size * ( j - 1 ), data + size * j) < 0 ) \
            j++; \
         if ( f(tmp, data + size * ( j - 1 )) >= 0 ) \
            break; \
         memcpy(data + size * ( i - 1 ), data + size * ( j - 1 ), size); \
         i = j; \
         j *= 2; \
      } \
      memcpy(data + size * ( i - 1 ), tmp, size); \
   }

int BkHsort(void *base, unsigned long n, unsigned long size,
   int (*f)(const void*, const void*), void (*OutputRec)(void*))
{
   void *tmp;
   unsigned long k;
   char *data;

   if ( BkMalloc(&tmp, size) == -1 )
      return -1;

   data = (char*)base;

   for (  k = n / 2; k != 0; k-- )
      sift(k, n);

   for (  k = n; k > 1; k-- ){
      OutputRec(data);
      memcpy(data, data + size * ( k - 1 ), size);
      sift(1, k - 1);
   }

   OutputRec(data);
   BkFree(tmp);
   return 0;
}

#define merge(ARG1, ARG2, ARG3) \
   { \
      unsigned long i, j, k, LEFT, MIDDLE, RIGHT; \
      LEFT = (ARG1); \
      MIDDLE = (ARG2); \
      RIGHT = (ARG3); \
      i = LEFT; \
      j = MIDDLE; \
      k = LEFT; \
      for (  ; i < MIDDLE && j < RIGHT; k++ ){ \
         if ( f(p1 + size * i, p1 + size * j) <= 0 ){ \
            memcpy(p2 + size * k, p1 + size * i, size); \
            i++; \
         } \
         else{ \
            memcpy(p2 + size * k, p1 + size * j, size); \
            j++; \
         } \
      } \
      if ( i < MIDDLE ) \
         memcpy(p2 + size * k, p1 + size * i, size * ( MIDDLE - i )); \
      if ( j < RIGHT ) \
         memcpy(p2 + size * k, p1 + size * j, size * ( RIGHT - j )); \
   }

void BkMsort(void *base, unsigned long n, unsigned long size,
   int (*f)(const void*, const void*), void *swap)
{
   char *p1, *p2;
   int flag;
   unsigned long i, left, middle, right, common;

   for (  flag = 0, common = 1, i = n; i > 1; ){
      if ( flag == 0 ){
         p1 = (char*)base;
         p2 = (char*)swap;
      }
      else{
         p1 = (char*)swap;
         p2 = (char*)base;
      }
      for (  left = 0; ; left += common * 2 ){
         middle = left + common;
         right = middle + common;
         if ( right <= n ){
            merge(left, middle, right);
            continue;
         }
         if ( middle <= n ){
            merge(left, middle, n);
            break;
         }
         memcpy(p2 + size * left, p1 + size * left, size * ( n - left ));
         break;
      }
      i = ( i + 1 ) / 2;
      flag = 1 - flag;
      common *= 2;
   }

   if ( flag == 1 )
      memcpy(base, swap, size * n);
}

int BkStrRCmp(const char *s1, const char *s2)
{
   if ( strlen(s1) < strlen(s2) )
      return 1;

   return strcmp(s1 + strlen(s1) - strlen(s2), s2);
}

void BkAddDataToList(BK_LIST *list, void *data)
{
   BK_LIST_NODE *node;

   (void)BkMalloc(&node, sizeof(BK_LIST_NODE));
   (void)BkMalloc(&node->data, list->len);
   memcpy(node->data, data, list->len);
   node->next = NULL;

   if ( list->n == 0 ){
      list->head = node;
      list->tail = node;
   }
   else
      list->tail->next = node;

   list->tail = node;
   list->n++;
}

void BkInitList(BK_LIST *list, int len)
{
   list->n = 0;
   list->len = len;
   list->head = NULL;
   list->tail = NULL;
}

int BkBinarySearch(void *array, int size, int n, void *data,
   int (*f)(const void*, const void*))
{
   int i, j, k, m, r;
   char *p;

   for ( m = -1, i = 0, j = n - 1; i <= j; ){
      k = (i + j) / 2;
      p = (char*)array + k * size;
      r = f(p, data);
      if ( r == 0 )
         m = k;
      if ( r < 0 )
         i = k + 1;
      else
         j = k - 1;
   }

   return m;
}

int BkCharIsInSet(char c, const char *set)
{
   if ( strchr(set, c) )
      return 1;
   else
      return 0;
}

void BkSmartArrayInit(BK_SMART_ARRAY *arr, size_t RecSize, int step)
{
   BK_ASSERT( arr != NULL );

   arr->size = RecSize;
   arr->n = 0;
   arr->step = step;
   (void)BkMalloc(&arr->p, RecSize);
}

void *BkSmartArrayLoad(BK_SMART_ARRAY *arr, int subscript)
{
   BK_ASSERT( arr != NULL );
   BK_ASSERT( subscript >= 0 && subscript < arr->n );

   return(arr->p + arr->size * subscript);
}

void BkSmartArrayStore(BK_SMART_ARRAY *arr, int subscript, void *data)
{
   int n;

   BK_ASSERT( arr != NULL && data != NULL );
   BK_ASSERT( subscript >= 0 );

   if ( subscript < arr->n )
      memcpy(arr->p + arr->size * subscript, data, arr->size);
   else{
      n = subscript - arr->n + 1;
      if ( n < arr->step )
         n = arr->step;
      (void)BkRealloc(&arr->p, arr->size * ( arr->n + n ));
      memset(arr->p + arr->size * arr->n, 0, arr->size * n);
      memcpy(arr->p + arr->size * subscript, data, arr->size);
      arr->n += n;
   }
}

int BkSmartArrayRecNum(BK_SMART_ARRAY *arr)
{
   BK_ASSERT( arr != NULL );

   return arr->n;
}

void BkSmartArrayDestory(BK_SMART_ARRAY *arr)
{
   BK_ASSERT( arr != NULL );

   BkFree(arr->p);
}

off_t BkFileSize(const char *File)
{
   int r;
   FILE *f;

   f = fopen(File, "rb");

   if ( f == NULL )
      return 0;

   fseek(f, 0, SEEK_END);
   r = ftell(f);
   fclose(f);
   return r;
}

int BkStrToInt(const char*Str)
{
   int Result = 0;

   sscanf(Str, "%d", &Result);
   return Result;
}

int BkHexStrToInt(const char*Str)
{
   int Result = 0;

   sscanf(Str, "%x", &Result);
   return Result;
}

float BkStrToFloat(const char *Str)
{
   float Result = 0;

   sscanf(Str, "%f", &Result);
   return Result;
}

double BkStrToDouble(const char *Str)
{
   double Result = 0;

   sscanf(Str, "%lf", &Result);
   return Result;
}

long double BkStrToLongDouble(const char *Str)
{
   long double Result = 0;

   sscanf(Str, "%Lf", &Result);
   return Result;
}

BK_SIG_FUNC *BkSignal(int SigNo, BK_SIG_FUNC *Func, int InterruptFlag)
{
   struct sigaction Act;
   struct sigaction OldAct;

   Act.sa_handler = Func;
   sigemptyset(&Act.sa_mask);
   Act.sa_flags = 0;

   if ( SigNo == SIGCHLD && Func == SIG_IGN )
   {
      Act.sa_flags |= SA_NOCLDWAIT;
   }

   if ( SigNo != SIGCHLD )
   {
      if ( InterruptFlag )
      {
#ifdef SA_INTERRUPT
         Act.sa_flags |= SA_INTERRUPT;
#endif
      }
      else
      {
#ifdef SA_RESTART
         Act.sa_flags |= SA_RESTART;
#endif
      }
   }

   if ( sigaction(SigNo, &Act, &OldAct) < 0 )
   {
      return SIG_ERR;
   }

   return OldAct.sa_handler;
}

time_t BkSubTimeval(const struct timeval *lhs, const struct timeval *rhs)
{
   return ( lhs->tv_sec - rhs->tv_sec ) * 1000 + ( lhs->tv_usec - rhs->tv_usec ) / 1000;
}

#ifdef __cplusplus
}
#endif
